﻿// -------------------- iSharePoint -------------------- //
// 
//  Company:	IT Complex, LLC
//  Project:	SmartLib
//  File name:	Curring.cs
//  Developer:	Igor Solomatov
//  Created:	04.11.2012
// 
// -------------------- iSharePoint -------------------- //

using System;

namespace Smart
{
	public static class FunctionalExts
	{
		#region Curry

		public static Func<T1, Func<T2, TResult>> Curry<T1, T2, TResult>(this Func<T1, T2, TResult> function)
		{
			return a1 => a2 => function(a1, a2);
		}

		public static Func<T1, Func<T2, Func<T3, TResult>>> Curry<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> function)
		{
			return a1 => a2 => a3 => function(a1, a2, a3);
		}

		public static Func<T1, Func<T2, Func<T3, Func<T4, TResult>>>> Curry<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> function)
		{
			return a1 => a2 => a3 => a4 => function(a1, a2, a3, a4);
		}

		public static Func<T1, Action<T2>> Curry<T1, T2>(this Action<T1, T2> action)
		{
			return a1 => a2 => action(a1, a2);
		}

		public static Func<T1, Func<T2, Action<T3>>> Curry<T1, T2, T3>(this Action<T1, T2, T3> action)
		{
			return a1 => a2 => a3 => action(a1, a2, a3);
		}

		public static Func<T1, Func<T2, Func<T3, Action<T4>>>> Curry<T1, T2, T3, T4>(this Action<T1, T2, T3, T4> action)
		{
			return a1 => a2 => a3 => a4 => action(a1, a2, a3, a4);
		}

		#endregion

		#region Apply Partial

		public static Func<TResult> ApplyPartial<T1, TResult>(this Func<T1, TResult> function, T1 a1)
		{
			return () => function(a1);
		}

		public static Func<T2, TResult> ApplyPartial<T1, T2, TResult>(this Func<T1, T2, TResult> function, T1 a1)
		{
			return a2 => function(a1, a2);
		}

		public static Func<TResult> ApplyPartial<T1, T2, TResult>(this Func<T1, T2, TResult> function, T1 a1, T2 a2)
		{
			return () => function(a1, a2);
		}

		public static Func<T2, T3, TResult> ApplyPartial<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> function, T1 a1)
		{
			return (a2, a3) => function(a1, a2, a3);
		}

		public static Func<T3, TResult> ApplyPartial<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> function, T1 a1, T2 a2)
		{
			return a3 => function(a1, a2, a3);
		}

		public static Func<TResult> ApplyPartial<T1, T2, T3, TResult>(this Func<T1, T2, T3, TResult> function, T1 a1, T2 a2, T3 a3)
		{
			return () => function(a1, a2, a3);
		}

		public static Func<T2, T3, T4, TResult> ApplyPartial<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> function, T1 a1)
		{
			return (a2, a3, a4) => function(a1, a2, a3, a4);
		}

		public static Func<T3, T4, TResult> ApplyPartial<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> function, T1 a1, T2 a2)
		{
			return (a3, a4) => function(a1, a2, a3, a4);
		}

		public static Func<T4, TResult> ApplyPartial<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> function, T1 a1, T2 a2, T3 a3)
		{
			return a4 => function(a1, a2, a3, a4);
		}

		public static Func<TResult> ApplyPartial<T1, T2, T3, T4, TResult>(this Func<T1, T2, T3, T4, TResult> function, T1 a1, T2 a2, T3 a3, T4 a4)
		{
			return () => function(a1, a2, a3, a4);
		}


		public static Action ApplyPartial<T1>(this Action<T1> action, T1 a1)
		{
			return () => action(a1);
		}

		public static Action<T2> ApplyPartial<T1, T2>(this Action<T1, T2> action, T1 a1)
		{
			return a2 => action(a1, a2);
		}

		public static Action ApplyPartial<T1, T2>(this Action<T1, T2> action, T1 a1, T2 a2)
		{
			return () => action(a1, a2);
		}

		public static Action<T2, T3> ApplyPartial<T1, T2, T3>(this Action<T1, T2, T3> action, T1 a1)
		{
			return (a2, a3) => action(a1, a2, a3);
		}

		public static Action<T3> ApplyPartial<T1, T2, T3>(this Action<T1, T2, T3> action, T1 a1, T2 a2)
		{
			return a3 => action(a1, a2, a3);
		}

		public static Action ApplyPartial<T1, T2, T3>(this Action<T1, T2, T3> action, T1 a1, T2 a2, T3 a3)
		{
			return () => action(a1, a2, a3);
		}

		public static Action<T2, T3, T4> ApplyPartial<T1, T2, T3, T4>(this Action<T1, T2, T3, T4> action, T1 a1)
		{
			return (a2, a3, a4) => action(a1, a2, a3, a4);
		}

		public static Action<T3, T4> ApplyPartial<T1, T2, T3, T4>(this Action<T1, T2, T3, T4> action, T1 a1, T2 a2)
		{
			return (a3, a4) => action(a1, a2, a3, a4);
		}

		public static Action<T4> ApplyPartial<T1, T2, T3, T4>(this Action<T1, T2, T3, T4> action, T1 a1, T2 a2, T3 a3)
		{
			return a4 => action(a1, a2, a3, a4);
		}

		public static Action ApplyPartial<T1, T2, T3, T4>(this Action<T1, T2, T3, T4> action, T1 a1, T2 a2, T3 a3, T4 a4)
		{
			return () => action(a1, a2, a3, a4);
		}

		#endregion
	}
}